package com.pan.insist.shiro;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.pan.insist.constant.CommonConstant;
import com.pan.insist.dao.RoleMapper;
import com.pan.insist.dao.UserMapper;
import com.pan.insist.model.LoginLogModel;
import com.pan.insist.model.MenuModel;
import com.pan.insist.model.UserModel;
import com.pan.insist.service.LoginLogService;
import com.pan.insist.service.MenuService;
import com.pan.insist.util.BaseUtil;
import com.pan.insist.util.IpUtils;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 用户实现shiro权限
 *
 * @author kaiji
 */
@Log4j2
public class UserRealm extends AuthorizingRealm {

    @Resource
    private UserMapper userMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private MenuService menuService;
    @Resource
    private LoginLogService loginLogService;

    /**
     * <p>
     * 检测登录信息
     * </p>
     * @param authenticationToken
     *  用户身份信息
     * @throws AuthenticationException
     *  获取身份信息异常
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        log.info("获取用户身份信息！");
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        UserModel userModel = userMapper.selectOne(new QueryWrapper<UserModel>()
                        .eq("phone", token.getUsername())
                        .eq("status", 0));
        if (null == userModel) {
            throw new AccountException("用户名不正确！");
        } else if (!userModel.getAuthCode().equals(new String((char[]) token.getCredentials()))) {
            throw new AccountException("验证码不正确");
        }

        // 修改用户信息
        userModel.setLoginIp(IpUtils.getIpFromRequest(BaseUtil.getRequest()));
        userModel.setLoginDate(LocalDateTime.now());
        userMapper.updateById(userModel);

        // 记录登录日志
        LoginLogModel loginLogModel = new LoginLogModel();
        loginLogModel.setLoginName(userModel.getUsername());
        loginLogModel.setLogName("登录日志");
        loginLogModel.setIp(userModel.getLoginIp());
        loginLogModel.setCreateDate(LocalDateTime.now());
        loginLogService.save(loginLogModel);

        return new SimpleAuthenticationInfo(userModel, userModel.getAuthCode(), getName());
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        log.info("————权限认证————");
        UserModel userModel = (UserModel) SecurityUtils.getSubject().getPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //获得该用户角色
        Set<String> roles = userMapper.getRoleByPhone(userModel.getPhone());
        //设置该用户拥有的角色
        info.setRoles(roles);

        Set<String> urls;
        boolean match = roles.stream().anyMatch(role -> StringUtils.equals(CommonConstant.ADMIN, role));
        if (match) {
            log.info("超级管理员闪亮登录");
            urls = menuService.list().stream().map(MenuModel::getUrl).collect(Collectors.toSet());
        } else {
            // 获取这些角色所拥有URL
            List<String> codes = new ArrayList<>(roles);
            urls = roleMapper.getUrlByRole(codes);
        }
        info.setStringPermissions(urls);
        return info;
    }

}
